/*
 * Copyright (C) 2000-2005 Philips Electronics N.V.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file gnu_license.txt.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
 * 
 */
#include <stdarg.h>
#include <front/mem.h>
#include <front/parse_support.h>

#include "fe_flags.h"
#include "statements.h"
#include "cfrontPrint.h"
#include "ast.h"
#include "init.h"

statement Copy_stat (statement e)
{
  statement a;
  a = Create_EmptyStat (no_srcinfo); 
  *a = *e;
  return a;
}

statement Deep_copy_stat (statement e)
{ if (e==NULL) return NULL;
  return Traverse_copy_statement (e, &cfront_copy_actions);
}

List_statement Deep_copy_stats (List_statement e)
{ if (e==NULL) return NULL;
  return Traverse_copy_List_statement (e, &cfront_copy_actions);
}

static void
decorate_stat (statement x)
{
  Scope sc = statement_old_scope(x);
  if (sc==NULL) sc = statement_scope(x);
  ast_decorate (statement, x, statement_cur_func(x), statement_previous(x), sc);
}

#if 0
static void decorate_stats (List_statement x, Scope scope, 
                            functionDefinition func, statement parent)
{
  ast_decorate (List_statement, x, func, parent, scope);
}
#endif

static void
set_props (statement x, statement t)
{
  statement_cur_func(x) = statement_cur_func(t);
  statement_previous(x) = statement_previous(t);
  statement_hook(x) = statement_hook(t);
  if (statement_old_scope(x) == statement_scope (x)) {
    /* X is not defining, copying scope will mess up obsoleteness */
    statement_scope(x) = statement_scope(t);
    statement_old_scope(x) = statement_old_scope(t);
  }
  if (statement_original(t) != NULL) {
    statement_original(x) = statement_original(t);
  } else {
    statement_original(x) = t;
  }
}

statement
replace_stat (statement x, statement y, int i)
{
  statement t;
  
  NOT_USED(i);
  
  t = Create_EmptyStat(no_srcinfo);
  *t = *x;
  *x = *y;
  
  set_props (x, t);
  decorate_stat (x);
  return x;
}

void
replace_stats (List_statement x, List_statement y, int i)
{
  functionDefinition f;
  Scope scope;
  statement parent;
  
  NOT_USED(i);
  
  f = statement_cur_func (List_statement_data(x));
  parent = statement_previous(List_statement_data(x));
  scope = statement_old_scope (List_statement_data(x));
  if (scope==NULL) scope = statement_scope (List_statement_data(x));
  
  *x = *y;
}

void
Parse_replace_statement (statement e, char *s, int n, ...)
{
  va_list p;
  statement result;

  va_start(p, n);
  Put_sub_trees (n, p);
  va_end(p);
  result = Parse_statement (s, 0);
  replace_stat (e, result, 0);
}

statement
statement_compound (statement s)
{
  statement p;
  
  for (p = statement_parent (s);
       p && statement_tag (p) != compound_statement_kind;
       p = statement_parent (p))
    { }
  return p;
}

void
append_statement (statement s1, statement s2)
{
  List_statement stats;
  statement p=s1, c;
  
  assert (statement_parent (s1));
  for (c = statement_parent (s1);
       c && statement_tag (c) != compound_statement_kind;
       c = statement_parent (c)) {
    p=c;
  }
  for (stats = compound_statement_body (c); stats; stats = TAIL(stats)) {
    if (HEAD(stats)==p) {
      FRONT_INSERT_HERE (stats, TAIL(stats), s2);
      return;
    }
  }
  abort();
}



/**********/

Scope func_scope (Scope s)
{
  for (; s; s = cfront_Scope_next(s)) {
    if (cfront_Scope_tag(s) == parameter_listScope_kind) return s;
#if 0
    if (cfront_Scope_tag(s) == ParDeclsScope_kind) return s;
#endif
    if (cfront_Scope_next(s) == NULL) return s;
    if (cfront_Scope_tag(cfront_Scope_next(s)) == cfrontScope_kind) return s;
  }
  
  return s;
}

Scope funcscope (statement x)
{ return func_scope (statement_scope(x));
}

/***********
 * Substitute e fopr d within s
*/

static struct s_void_cfront_TraverseTable replace_actions;

static declarator the_decl;
static expression the_expr ;

static void Post_replace_var (expression e)
{
  if (IdExpr_decl(e) != the_decl) return;
  replace_expr (e, Copy_expr(the_expr), 0);
}

statement Subst_stat (statement s, declarator d, expression e, Bool copy)
{
  replace_actions.action_IdExpr[POST_ACTION] = Post_replace_var;
  the_decl = d;
  the_expr = e;

  if (copy) s = Traverse_copy_statement(s, &cfront_copy_actions);
  Traverse_void_statement (s, &replace_actions);
  return s;
}

/*****/

static void MyPRINT_statement (statement s)
{  
  if (s!=NULL && statement_tag(s) == ExprStat_kind &&
      expression_tag(ExprStat_expr(s)) == StatExpr_kind) {
    MyPRINT_statement (StatExpr_stat(ExprStat_expr(s)));
    return;
  }
      
  Print_statement (s);
}

void init_stat_tables (void)
{ /* Overwrite default print statement */
  cfront_print_actions.action_statement[PRE_ACTION] = MyPRINT_statement;
}
